//
//  GameLayer.mm
//  CutCut
//
//  Created by Bullet Hermit on 12-11-2.
//  Copyright 紫竹飞燕 2012年. All rights reserved.
//

// Import the interfaces
#import "GameLayer.h"

// Needed to obtain the Navigation Controller
#import "AppDelegate.h"
#import "Watermelon.h"
#import "Strawberry.h"
#import "Pineapple.h"
#import "Grapes.h"
#import "Banana.h"
#import "Bomb.h"
#import "MessageLayer.h"
#import "WelcomeLayer.h"
#import "CCBReader.h"
enum {
	kTagParentNode = 1,
};
enum
{
    kLayerTagGame=0,
    kLayerTagUI,
    kLayerTagMsg,
}kLayerTag;

#pragma mark - GameLayer

@interface GameLayer(PrivateMethods)
-(void) initPhysics;
-(void) initSprites;
-(void) initHUD;
-(id) initWithGameMode:(kGameMode)mode;
-(void)checkAndSliceObjects;
-(void) clearSlices;
-(void) tossSprite:(PolygonSprite*)sprite;

-(void) spriteLoop;
-(void) clearSprite;
-(void) reset;
-(void)endGame;
-(void)substractLife;
@end 
int comparator(const void* a,const void* b)
{
    const b2Vec2* _a = (const b2Vec2*)a;
    const b2Vec2* _b = (const b2Vec2*)b;
    if(_a->x>_b->x)
    {
        return 1;
    }
    else if(_a->x<_b->x)
    {
        return -1;
    }
    return 0;
}
@implementation GameLayer
@synthesize cache = _cache;
@synthesize blades = _blades;
@synthesize swoosh = _swoosh;
static CCScene* instanceOfGame;
+(CCScene *) scene
{
	// 'scene' is an autorelease object.
	instanceOfGame = [CCScene node];
	
	// 'layer' is an autorelease object.
	GameLayer *layer = [GameLayer node];
	
	// add layer as a child to scene
	[instanceOfGame addChild: layer];
	
    MessageLayer* msg = [MessageLayer nodeWith:layer];
    [instanceOfGame addChild:msg z:1 tag:kLayerTagMsg];
    msg.visible=NO;
	// return the scene
	return instanceOfGame;
}
+(CCScene*) sceneWithGameMode:(kGameMode)mode
{
    // 'scene' is an autorelease object.
	instanceOfGame = [CCScene node];
	
	// 'layer' is an autorelease object.
	GameLayer *layer = [GameLayer nodeWithGameMode:mode];
	
	// add layer as a child to scene
	[instanceOfGame addChild: layer];
    MessageLayer* msg = [MessageLayer nodeWith:layer];
    [instanceOfGame addChild:msg z:1 tag:kLayerTagMsg];
    msg.visible=NO;
	// return the scene
	return instanceOfGame;
}
+(GameLayer*)nodeWithGameMode:(kGameMode)mode
{
    return [[[self alloc] initWithGameMode:mode] autorelease];
}
#pragma mark init
-(id) initWithGameMode:(kGameMode)mode
{
    if( (self=[super init]))
    {
        gameMode=mode;
        
        _nextTossTime = CACurrentMediaTime()+1;
        _queuedForToss = 0;
        //enable event
        self.isTouchEnabled = YES;
        self.isAccelerometerEnabled = YES;
        CGSize screen = [CCDirector sharedDirector].winSize;
        CCSprite* bg = [CCSprite spriteWithFile:@"bg.png"];
        bg.position = ccp(screen.width/2,screen.height/2);
        //init particles
        _bladeSparkle = [CCParticleSystemQuad particleWithFile:@"blade_sparkle.plist"];
        [self addChild:_bladeSparkle z:3];
        [_bladeSparkle stopSystem];
        //CCParticleSystemQuad* sunPollen = [CCParticleSystemQuad particleWithFile:@"sun_pollen.plist"];
        // [self addChild:sunPollen z:3];
        [self addChild:bg z:0];
        //init sound
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"explosion.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"lose_life.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"smallcut.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"squash.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"toss_bomb.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"toss_consecutive.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"toss_simultaneous.caf"];
        _swoosh = [[SimpleAudioEngine sharedEngine] soundSourceForFile:@"swoosh.caf"];
        
        
        _currentTime = 0;
        _previousTime = 0;
        
        CCMenuItemImage* back=[CCMenuItemImage itemWithNormalImage:@"pause.png" selectedImage:@"pause.png" target:self selector:@selector(backMenu)];
        CCMenu* menuUI=[CCMenu menuWithItems:back, nil];
        menuUI.position=ccp(screen.width*0.5 ,screen.height-30);
        [self addChild:menuUI];
        [self initPhysics];
        [self scheduleUpdate];
        
    }
	return self;
}
-(id) init
{
	if( (self=[super init])) 
    {
        //gameMode=kGameModeTime;
        
        _nextTossTime = CACurrentMediaTime()+1;
        _queuedForToss = 0;
        //enable event
        self.isTouchEnabled = YES;
        self.isAccelerometerEnabled = YES;
        CGSize screen = [CCDirector sharedDirector].winSize;
        CCSprite* bg = [CCSprite spriteWithFile:@"bg.png"];
        bg.position = ccp(screen.width/2,screen.height/2);
        //init particles
        _bladeSparkle = [CCParticleSystemQuad particleWithFile:@"blade_sparkle.plist"];
        [self addChild:_bladeSparkle z:3];
        [_bladeSparkle stopSystem];
        //CCParticleSystemQuad* sunPollen = [CCParticleSystemQuad particleWithFile:@"sun_pollen.plist"];
       // [self addChild:sunPollen z:3];
        [self addChild:bg z:0];
        //init sound
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"explosion.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"lose_life.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"smallcut.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"squash.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"toss_bomb.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"toss_consecutive.caf"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"toss_simultaneous.caf"];
        _swoosh = [[SimpleAudioEngine sharedEngine] soundSourceForFile:@"swoosh.caf"];

        
        _currentTime = 0;
        _previousTime = 0;
        CCMenuItemImage* back=[CCMenuItemImage itemWithNormalImage:@"pause.png" selectedImage:@"pause.png" target:self selector:@selector(backMenu)];
        CCMenu* menuUI=[CCMenu menuWithItems:back, nil];
        menuUI.position=ccp(screen.width*0.5 ,screen.height-30);
        [self addChild:menuUI];
         [self initPhysics];
         [self scheduleUpdate];
        
    }
	return self;
}

-(void) dealloc
{
	delete world;
	world = NULL;
	
	delete m_debugDraw;
	m_debugDraw = NULL;
	
    [_cache release];
    _cache = nil;
    [_blades release];
    _blades = nil;
   // [self.swoosh release];
    //self.swoosh = nil;
	[super dealloc];
}	


-(void) initPhysics
{
	CGSize s = [[CCDirector sharedDirector] winSize];
	
	b2Vec2 gravity;
	gravity.Set(0.0f, -4.5f);
	world = new b2World(gravity);
	
	
	// Do we want to let bodies sleep?
	world->SetAllowSleeping(true);
	
	world->SetContinuousPhysics(true);
	
	m_debugDraw = new GLESDebugDraw( PTM_RATIO );
	world->SetDebugDraw(m_debugDraw);
    
	uint32 flags = 0;
	//flags += b2Draw::e_shapeBit;
	//		flags += b2Draw::e_jointBit;
	//		flags += b2Draw::e_aabbBit;
	//		flags += b2Draw::e_pairBit;
	//		flags += b2Draw::e_centerOfMassBit;
	m_debugDraw->SetFlags(flags);		
	
	
	// Define the ground body.
	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(0, 0); // bottom-left corner
	
	// Call the body factory which allocates memory for the ground body
	// from a pool and creates the ground box shape (also from a pool).
	// The body is also added to the world.
	b2Body* groundBody = world->CreateBody(&groundBodyDef);
	
	// Define the ground box shape.
	b2EdgeShape groundBox;		
	

	// top
	groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
	groundBody->CreateFixture(&groundBox,0);
	// left
	groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
	groundBody->CreateFixture(&groundBox,0);
	
	// right
	groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
	groundBody->CreateFixture(&groundBox,0);
    [self initSprites];
    [self initHUD];
}

-(void) initSprites
{
    _rayCastCallback = new RayCastCallback();
    _blades = [[CCArray alloc] initWithCapacity:3];
    CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:@"streak.png"];
    for (int i =0; i!=3; ++i) {
        CCBlade* blade = [CCBlade bladeWithMaximumPoint:50];
        blade.autoDim = NO;
        blade.texture = texture;
        [self addChild:blade z:2];
        [_blades addObject:blade];
    }
    
    _cache = [[CCArray alloc] initWithCapacity:53];
    for (int i = 0; i < 10; i++)
    {
        PolygonSprite *sprite = [[Watermelon alloc] initWithWorld:world];
        sprite.position = ccp(-64*(i+1),-64);
        [self addChild:sprite.splurt z:1];
        [self addChild:sprite z:1];
        [_cache addObject:sprite];
    }
    for (int i = 0; i < 10; i++)
    {
        PolygonSprite *sprite = [[Strawberry alloc] initWithWorld:world];
        sprite.position = ccp(-64*(i+1),-64);
        [self addChild:sprite.splurt z:1];
        [self addChild:sprite z:1];
        [_cache addObject:sprite];
    }
    for (int i = 0; i < 10; i++)
    {
        PolygonSprite *sprite = [[Pineapple alloc] initWithWorld:world];
        sprite.position = ccp(-64*(i+1),-64);
        [self addChild:sprite.splurt z:1];
        [self addChild:sprite z:1];
        [_cache addObject:sprite];
    }
    for (int i = 0; i < 10; i++)
    {
        PolygonSprite *sprite = [[Grapes alloc] initWithWorld:world];
        sprite.position = ccp(-64*(i+1),-64);
        [self addChild:sprite.splurt z:1];
        [self addChild:sprite z:1];
        [_cache addObject:sprite];
    }
    for (int i = 0; i < 10; i++)
    {
        PolygonSprite *sprite = [[Banana alloc] initWithWorld:world];
        sprite.position = ccp(-64*(i+1),-64);
        [self addChild:sprite.splurt z:1];
        [self addChild:sprite z:1];
        [_cache addObject:sprite];
    }
    
    for (int i = 0; i < 3; i++)
    {
        PolygonSprite *sprite = [[Bomb alloc] initWithWorld:world];
        sprite.position = ccp(-64*(i+1),-64);
        [self addChild:sprite.splurt z:1];
        [self addChild:sprite z:1];
        [_cache addObject:sprite];
    }
}
-(void) initHUD
{
    
    _cuts=0;
    
    CGSize screen = [[CCDirector sharedDirector] winSize];
    if (gameMode==kGameModeLife) {
        _lives = 3;
        //init life icon
        for (int i=0; i!=3; ++i ) {
            CCSprite* cross = [CCSprite spriteWithFile:@"x_unfilled.png"];
            cross.position = ccp(screen.width - cross.contentSize.width/2 - i*cross.contentSize.width, screen.height - cross.contentSize.height/2);
            [self addChild:cross z:3];
        }
    }
    else
    {
        initTime=3600;
        //init time icon
        CCSprite* timeIcon = [CCSprite spriteWithFile:@"clock.png"];
        timeIcon.position = ccp(screen.width - timeIcon.contentSize.width-30, screen.height - timeIcon.contentSize.height/2);
        [self addChild:timeIcon];
        //init time label
        _timeLabel = [CCLabelTTF labelWithString:@"0" fontName:@"Helvetica Neue" fontSize:30];
        _timeLabel.anchorPoint = ccp(0,0.5);
        _timeLabel.position = ccp(timeIcon.position.x + timeIcon.contentSize.width/2 +  _timeLabel.contentSize.width/2,timeIcon.position.y);
        [self addChild:_timeLabel z:3];
    }
    //init cut icon
    CCSprite* cutsIcon = [CCSprite spriteWithFile:@"fruit_cut.png"];
    cutsIcon.position = ccp(cutsIcon.contentSize.width/2, screen.height - cutsIcon.contentSize.height/2);
    [self addChild:cutsIcon];
    //init cuts label
    _cutLabel = [CCLabelTTF labelWithString:@"0" fontName:@"Helvetica Neue" fontSize:30];
    _cutLabel.anchorPoint = ccp(0,0.5);
    _cutLabel.position = ccp(cutsIcon.position.x + cutsIcon.contentSize.width/2 +  _cutLabel.contentSize.width/2,cutsIcon.position.y);
    [self addChild:_cutLabel z:3];
    
}
-(void) pauseGame
{
    [self pauseSchedulerAndActions];
    self.isTouchEnabled=NO;
    CCLayer* msg = (CCLayer*)[instanceOfGame getChildByTag:kLayerTagMsg];
    msg.visible=YES;
    
}
-(void) resumeGame
{
    [self resumeSchedulerAndActions];
    self.isTouchEnabled=YES;
    CCLayer* msg = (CCLayer*)[instanceOfGame getChildByTag:kLayerTagMsg];
    msg.visible=NO;
}
-(void) backMenu
{
    CCScene* welcomeUI = [CCBReader sceneWithNodeGraphFromFile:@"WelcomeUI.ccbi"];
    CCLOG(@"ss");
	[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:welcomeUI ]];
 
}
-(void) reset
{
    CCScene *scene = [CCScene node];  
    [scene addChild:[GameLayer node]];  
    [[CCDirector sharedDirector] replaceScene:[CCTransitionFadeBL transitionWithDuration:1.2f scene:scene]];  

   
}
-(void) endGame
{
    
    [self unscheduleUpdate];
    CCMenuItemLabel *label = [CCMenuItemLabel itemWithLabel:[CCLabelTTF labelWithString:@"RESTART"fontName:@"Helvetica Neue" fontSize:50] target:self selector:@selector(reset)];
    CCMenu *menu = [CCMenu menuWithItems:label, nil];
    CGSize screen = [[CCDirector sharedDirector] winSize];
    menu.position = ccp(screen.width/2, screen.height/2);
    [self addChild:menu z:4];
    
}
-(void) substractLife
{
    if (gameMode!=kGameModeLife) {
        return;
    }
    CGSize screen = [[CCDirector sharedDirector] winSize];
    _lives--;
    CCSprite *lostLife = [CCSprite spriteWithFile:@"x_filled.png"];
    lostLife.position = ccp(screen.width - lostLife.contentSize.width/2 - _lives*lostLife.contentSize.width, screen.height - lostLife.contentSize.height/2);
    [self addChild:lostLife z:4];
    
    if (_lives <= 0)
    {
        [self endGame];
    }
    [[SimpleAudioEngine sharedEngine] playEffect:@"lose_life.caf"];
}
-(void) substractTime:(ccTime)delta
{
    initTime -= delta;
	int currentTime = (int)initTime;
	if (initTime>0)
	{
	
		[_timeLabel setString:[NSString stringWithFormat:@"%i", currentTime/60]];
	}
    else
    {
        [_timeLabel setString:[NSString stringWithFormat:@"%i", currentTime/60]];
        [self endGame];
    }
}

-(BOOL) isVerticesAccept:(b2Vec2 *)vertices vertexCount:(int)count
{
    
    //TODO:----
    //check point 1:3<counts<max
    if(count<3 || count>b2_maxPolygonVertices)
        return NO;
    
    //check point 2:distance between points >b2_epsilion
    for (int i=0; i!=count; ++i) {
        int32 i1 = i;
        int32 i2 = (i+1<count-1?i+1:0);
        b2Vec2 pointLen = vertices[i2]-vertices[i1];
        if (pointLen.LengthSquared()<=b2_epsilon*b2_epsilon) {
            return NO;
        }
    }
    //check point 3:the area of polygon >b2_epsilion
    float32 area = 0.0f;
    b2Vec2 pRef(0.0f,0.0f); 
    for (int i=0; i!=count; ++i) {
        b2Vec2 p1 = pRef;
        b2Vec2 p2=vertices[i];
        b2Vec2 p3 = (i+1<count?vertices[i+1]:vertices[0]);
        
        b2Vec2 edge1 = p2-p1;
        b2Vec2 edge2 = p3-p1;
        float32 D = b2Cross(edge1, edge2);
        float32 triangle = 0.5f*D;
        area += triangle;
    }


    if (area<=0.00001) {
        return NO;

    }
    //---

     
    //----
    //check point 4:must convex!!NOT CONCAV
    float determinant;
    b2Vec2 v1 = vertices[0]-vertices[count-1];
    b2Vec2 v2 = vertices[1] - vertices[0];
    float referDeterminant = calculate_determinant_2x2(v1.x , v1.y , v2.x , v2.y);
    for (int i=1; i!=count-1; ++i) {
        v1=v2;
        v2 = vertices[i+1]-vertices[i];
        determinant = calculate_determinant_2x2(v1.x , v1.y , v2.x , v2.y);
        if (referDeterminant*determinant<0) {
            return NO;
        }
    }
    v1 = v2;
    v2 = vertices[0]-vertices[count-1];
    determinant = calculate_determinant_2x2(v1.x , v1.y , v2.x , v2.y);
    if (referDeterminant*determinant<0) {
        return NO;
    }
    
    return YES;
}
-(b2Body*) createBodyWithPosition:(b2Vec2)position rotation:(float)rotation vertices:(b2Vec2 *)vertices vertexCount:(int32)count density:(float)density friction:(float)friction restitution:(float)restitution
{
    b2BodyDef bodyDef;
    bodyDef.position = position;
    bodyDef.type = b2_dynamicBody;
    bodyDef.angle = rotation;
    b2Body* body = world->CreateBody(&bodyDef);
    
    b2FixtureDef fixtureDef;
    fixtureDef.density = density;
    fixtureDef.friction = friction;
    fixtureDef.restitution = restitution;
    
    
    b2PolygonShape shape;
    shape.Set(vertices, count);
    fixtureDef.shape = &shape;
    body->CreateFixture(&fixtureDef);
    return body;
    
}
-(b2Vec2*) arrangeVertices:(b2Vec2 *)vertices vertexCount:(int)count
{
    b2Vec2 referencePointA,referencePointB;
    qsort(vertices, count, sizeof(b2Vec2), comparator);
    
    referencePointA = vertices[0];
    referencePointB = vertices[count-1];
    
    int iClockWise = count-1;
    int iCountClockWise = 1;
    float determinator;
    b2Vec2* sortVertices = (b2Vec2*)calloc(count,(sizeof(b2Vec2)));
    sortVertices[0] = vertices[0 ];
    for (int i=1; i<count-1; ++i ) {
        determinator = calculate_determinant_2x3(referencePointA.x , referencePointA.y, referencePointB.x, referencePointB.y , vertices[i].x , vertices[i].y );
        if(determinator<0)
        {
            sortVertices[iCountClockWise++] = vertices[i ];
        }
        else 
        {
            sortVertices[iClockWise--] = vertices[i];
        }
    }
    sortVertices[iCountClockWise] = vertices[count-1];
    
    return sortVertices;
}
-(void) tossSprite:(PolygonSprite*)sprite
{
    CGSize screen = [[CCDirector sharedDirector] winSize];
    CGPoint randomPosition = ccp(frandom_range(100, screen.width-164), -64);
    float randomAngularVelocity = frandom_range(-1, 1);
    
    float xModifier = 50*(randomPosition.x - 100)/(screen.width - 264);
    float min = -25.0 - xModifier;
    float max = 75.0 - xModifier;
    
    float randomXVelocity = frandom_range(min,max);
    float randomYVelocity = frandom_range(250, 300);
    
    sprite.state = kStateTossed;
    sprite.position = randomPosition;
    [sprite activeCollisions];
    sprite.body->SetLinearVelocity(b2Vec2(randomXVelocity/PTM_RATIO,randomYVelocity/PTM_RATIO));
    sprite.body->SetAngularVelocity(randomAngularVelocity);
}
-(void) spriteLoop
{
    double curTime = CACurrentMediaTime();
    
    //step 1
    if (curTime > _nextTossTime)
    { 
        PolygonSprite *sprite;
        int chance = arc4random()%2;
        if (chance == 0)
        {
            CCARRAY_FOREACH(_cache, sprite)
            {
                if (sprite.state == kStateIdle && sprite.type == kTypeBomb)
                {
                    [[SimpleAudioEngine sharedEngine] playEffect:@"toss_bomb.caf"];
                    [self tossSprite:sprite];
                    break;
                }
            }
        }
        
       
        
        int random = random_range(0, 4);
        //step 2
        Type type = (Type)random;
        if (_currentTossType == kTossTypeConsecutive && _queuedForToss > 0)
        {
            CCARRAY_FOREACH(_cache, sprite)
            {
                if (sprite.state == kStateIdle && sprite.type == type)
                {
                    [[SimpleAudioEngine sharedEngine] playEffect:@"toss_consecutive.caf"];
                    [self tossSprite:sprite];
                    _queuedForToss--;
                    break;
                }
            }
        }
        else
        { //step 3
            _queuedForToss = random_range(3, 8);
            int tossType = random_range(0,1);
            
            _currentTossType = (kTossType)tossType;
            //step 4
            if (_currentTossType == kTossTypeSimultaneous)
            {
                CCARRAY_FOREACH(_cache, sprite)
                {
                    if (sprite.state == kStateIdle && sprite.type == type)
                    {
                        [[SimpleAudioEngine sharedEngine] playEffect:@"toss_simultaneous.caf"];
                        [self tossSprite:sprite];
                        _queuedForToss--;
                        random = random_range(0, 4);
                        type = (Type)random;
                        
                        if (_queuedForToss == 0)
                        {
                            break;
                        }
                    }
                }
            } //step 5
            else if (_currentTossType == kTossTypeConsecutive)
            {
                CCARRAY_FOREACH(_cache, sprite)
                {
                    if (sprite.state == kStateIdle && sprite.type == type)
                    {
                        [[SimpleAudioEngine sharedEngine] playEffect:@"toss_consecutive.caf"];
                        [self tossSprite:sprite];
                        _queuedForToss--;
                        break;
                    }
                }
            }
        }
        //step 6
        if (_queuedForToss == 0)
        {
            _tossInterval = frandom_range(2,3);
            _nextTossTime = curTime + _tossInterval;
        }
        else 
        {
            _tossInterval = frandom_range(0.3,0.8);
            _nextTossTime = curTime + _tossInterval;
        }
    }
}
-(void) splitPolygonSprite:(PolygonSprite *)sprite
{
    
    //the new polygon sprite
    PolygonSprite* sprite1;
    PolygonSprite* sprite2;
    //store vertex
    b2Vec2* vertices1 = (b2Vec2*)calloc(24,(sizeof(b2Vec2)));
    b2Vec2* vertices2 =  (b2Vec2*)calloc(24,(sizeof(b2Vec2)));
    b2Vec2* verticesSort1 , *verticesSort2;
    int vertexCount1 =0;
    int  vertexCount2=0;
    
    
    //get vertex count and fixture
    b2Fixture* originalFixture= sprite.body->GetFixtureList();
    b2PolygonShape* originalShape = (b2PolygonShape*)originalFixture->GetShape();
    int count = originalShape->GetVertexCount();
    float determinator;
    //step1:allocate the entry point and exit point to two vertices
    
    vertices1[vertexCount1++] = sprite.entryPoint;
    vertices1[vertexCount1++] = sprite.exitPoint;
    vertices2[vertexCount2++] = sprite.entryPoint;
    vertices2[vertexCount2++] = sprite.exitPoint;
    //step2:allocate residual vertices
    for(int i = 0;i!=count;++i)
    {
        b2Vec2 pointTemp =originalShape->GetVertex(i);
        b2Vec2 diffPoint1 = pointTemp - sprite.entryPoint;
        b2Vec2 diffPoint2 = pointTemp - sprite.exitPoint;
        if((diffPoint1.x!=0||diffPoint1.y!=0)&&(diffPoint2.x!=0||diffPoint2.y!=0))
        {
            determinator = calculate_determinant_2x3(sprite.entryPoint.x , sprite.entryPoint.y,  sprite.exitPoint.x , sprite.exitPoint.y,pointTemp.x , pointTemp.y  ); 
            if(determinator>0)
            {
                vertices1[vertexCount1++] = pointTemp;
            }
            else 
            {
                vertices2[vertexCount2++] = pointTemp;
            }
        }
    }
    //step3:sort the vertices by count-clockwise
    
    
    verticesSort1=[self arrangeVertices:vertices1 vertexCount:vertexCount1];
    
    verticesSort2 = [self arrangeVertices:vertices2 vertexCount:vertexCount2];
    //step4:judge the vertices whether could be enable
    BOOL isVertices1Accept =NO;
    isVertices1Accept = [self isVerticesAccept:verticesSort1 vertexCount:vertexCount1];
    
    BOOL isVertices2Accept =NO;
    isVertices2Accept= [self isVerticesAccept:verticesSort2 vertexCount:vertexCount2];
    //step5:create two polygon sprite by verticesSort array
    if(isVertices1Accept&&isVertices2Accept)
    {
        
        b2Vec2 worldEntry = sprite.body->GetWorldPoint(sprite.entryPoint);
        b2Vec2 worldExit = sprite.body->GetWorldPoint(sprite.exitPoint);
        float angle = ccpToAngle(ccpSub(ccp(worldExit.x,worldExit.y), ccp(worldEntry.x,worldEntry.y)));
        CGPoint vector1 = ccpForAngle(angle + 1.570796);
        CGPoint vector2 = ccpForAngle(angle - 1.570796);
        float midX = midpoint(worldEntry.x, worldExit.x);
        float midY = midpoint(worldEntry.y, worldExit.y);
        //particle
        b2Vec2 convertedWorldEntry = b2Vec2(worldEntry.x*PTM_RATIO,worldEntry.y*PTM_RATIO);
        b2Vec2 convertedWorldExit = b2Vec2(worldExit.x*PTM_RATIO,worldExit.y*PTM_RATIO);
        float splurtMidX = midpoint(convertedWorldEntry.x, convertedWorldExit.x);
        float splurtMidY = midpoint(convertedWorldEntry.y, convertedWorldExit.y);
        sprite.splurt.position = ccp(splurtMidX,splurtMidY);
        [sprite.splurt resetSystem];
        [[SimpleAudioEngine sharedEngine] playEffect:@"squash.caf"];
        b2Body* body1 = [self createBodyWithPosition:sprite.body->GetPosition() rotation:sprite.body->GetAngle() vertices:verticesSort1 vertexCount:vertexCount1 density:originalFixture->GetDensity() friction:originalFixture->GetFriction() restitution:originalFixture->GetRestitution()];
        sprite1 = [PolygonSprite spriteWithTexture:sprite.texture body:body1 original:NO];
        [self addChild:sprite1 z:1];
        sprite1.body->ApplyLinearImpulse(b2Vec2(2*body1->GetMass()*vector1.x,2*body1->GetMass()*vector1.y), b2Vec2(midX,midY));
        
        
        
        b2Body* body2 = [self createBodyWithPosition:sprite.body->GetPosition() rotation:sprite.body->GetAngle() vertices:verticesSort2 vertexCount:vertexCount2 density:originalFixture->GetDensity() friction:originalFixture->GetFriction() restitution:originalFixture->GetRestitution()];
        sprite2 = [PolygonSprite spriteWithTexture:sprite.texture body:body2 original:NO];
        [self addChild:sprite2 z:1];
        sprite2.body->ApplyLinearImpulse(b2Vec2(2*body2->GetMass()*vector2.x,2*body2->GetMass()*vector2.y), b2Vec2(midX,midY));

        if (sprite.isOriginal)
        { 
            sprite.state = kStateIdle;
            [sprite deactiveCollisions];
            sprite.position = ccp(-256,-256);   //cast them faraway
            sprite.isSliceEntered = NO;
            sprite.isSliceExited = NO;
            sprite.entryPoint.SetZero();
            sprite.exitPoint.SetZero();
            if (sprite.type == kTypeBomb)
            {
                [[SimpleAudioEngine sharedEngine] playEffect:@"explosion.caf"];
                [self substractLife];
            }
            else
            {
                //placeholder
            }
        }
        else 
        {
            [[SimpleAudioEngine sharedEngine] playEffect:@"smallcut.caf"];
            world->DestroyBody(sprite.body);
            [self removeChild:sprite cleanup:YES];
        }
        ++_cuts;
        [_cutLabel setString:[NSString stringWithFormat:@"%d",_cuts]];
    }
    else
    {
        //if the vertices don't be accept,canceling this slice
        sprite.isSliceEntered = NO;
        sprite.isSliceExited = NO;
    }
    
    free(vertices1);
    free(vertices2);
    free(verticesSort1);
    free(verticesSort2);
    
}
-(void)checkAndSliceObjects
{
    double curTime = CACurrentMediaTime();
    for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
    {
        if (b->GetUserData() != NULL) {
            PolygonSprite *sprite = (PolygonSprite*)b->GetUserData();

            if (sprite.isSliceEntered && curTime > sprite.sliceEntryTime) 
            {
                sprite.isSliceEntered = NO;
            }
            else if (sprite.isSliceEntered && sprite.isSliceExited)
            {
                CCLOG(@"split begin");
                [self splitPolygonSprite:sprite];
            }
        }
    }
    [self clearSprite];
}
#pragma mark update
-(void) draw
{
	//
	// IMPORTANT:
	// This is only for debug purposes
	// It is recommend to disable it
	//
	[super draw];
	
	ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
	
	kmGLPushMatrix();
	ccDrawLine(_startPoint, _endPoint);
	world->DrawDebugData();	
	
	kmGLPopMatrix();
}

-(void) update: (ccTime) dt
{
	//It is recommended that a fixed time step is used with Box2D for stability
	//of the simulation, however, we are using a variable time step here.
	//You need to make an informed choice, the following URL is useful
	//http://gafferongames.com/game-physics/fix-your-timestep/
	
	int32 velocityIterations = 8;
	int32 positionIterations = 1;
	[self checkAndSliceObjects];
    if ([_blade.path count] > 3) {
        _deltaRemainder+=dt*60*1.2;
        int pop = (int)roundf(_deltaRemainder);
        _deltaRemainder-=pop;
        [_blade pop:pop];
    }
    [self spriteLoop];
    if (gameMode==kGameModeTime) {
        [self substractTime:dt];
    }
	// Instruct the world to perform a single step of simulation. It is
	// generally best to keep the time step and iterations fixed.
	world->Step(dt, velocityIterations, positionIterations);	
}

-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   
        UITouch* touch = [touches anyObject];
		CGPoint location = [touch locationInView: [touch view]];
		location = [[CCDirector sharedDirector] convertToGL: location];
		_endPoint = location;
		_startPoint = location;
        CCBlade *blade= [_blades objectAtIndex:0];
        CCARRAY_FOREACH(_blades, blade)
        {
            if (blade.path.count == 0)
            {
                _blade = blade;
                [_blade push:location];
                break;
            }
        }

        _bladeSparkle.position=location;
        [_bladeSparkle resetSystem];
	
    
}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{

        UITouch* touch = [touches anyObject];
		CGPoint location = [touch locationInView: [touch view]];
		location = [[CCDirector sharedDirector] convertToGL: location];
		_endPoint = location;
        ccTime deltaTime = _currentTime - _previousTime;
        _previousTime = _currentTime;
        CGPoint oldPosition = _bladeSparkle.position;
        [_blade push:location];
        if (ccpDistance(_bladeSparkle.position, oldPosition) / deltaTime > 1000)
        {
            if (!_swoosh.isPlaying)
            {
                [_swoosh play];
            }
        }
        _bladeSparkle.position=location;
	
    if (ccpLengthSQ(ccpSub(_startPoint, _endPoint))>25) {
        world->RayCast(_rayCastCallback, b2Vec2(_startPoint.x / PTM_RATIO, _startPoint.y / PTM_RATIO), b2Vec2(_endPoint.x/PTM_RATIO,_endPoint.y/PTM_RATIO));
        world->RayCast(_rayCastCallback, b2Vec2(_endPoint.x/PTM_RATIO,_endPoint.y/PTM_RATIO), b2Vec2(_startPoint.x / PTM_RATIO, _startPoint.y / PTM_RATIO));
        _startPoint = _endPoint;
    }
    
    
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	
    UITouch* touch = [touches anyObject];
		CGPoint location = [touch locationInView: [touch view]];
		location = [[CCDirector sharedDirector] convertToGL: location];
		_endPoint = location;
        [_blade dim:YES];
		
	
    [_bladeSparkle stopSystem];
    [self clearSlices];
}
-(void) clearSlices
{
    for (b2Body* body=world->GetBodyList(); body; body=body->GetNext())
    {
        PolygonSprite* ps = (PolygonSprite*)body->GetUserData();
        ps.isSliceEntered = NO;
        ps.isSliceExited = NO;
    }
}
-(void) clearSprite
{
    //check all sprite
    PolygonSprite* sprite;
    CCARRAY_FOREACH(_cache, sprite)
    {
        if(sprite.state==kStateTossed)
        {
            CGPoint position = ccp(sprite.body->GetPosition().x*PTM_RATIO,sprite.body->GetPosition().y*PTM_RATIO);
            float velocity = sprite.body->GetAngularVelocity();
            if(position.y<-64&&velocity<0)
            {
                sprite.state = kStateIdle;
                sprite.isSliceEntered = NO;
                sprite.isSliceExited = NO;
                sprite.entryPoint.SetZero();
                sprite.exitPoint.SetZero();
                sprite.position = ccp(-64,-64);
                sprite.body->SetLinearVelocity(b2Vec2(0.0,0.0));
                sprite.body->SetAngularVelocity(0.0);
                [sprite deactiveCollisions];
                if (sprite.type!=kTypeBomb) {
                    [self substractLife];
                }
            }
        }
    }
    //check all piece
    CGSize screen = [[CCDirector sharedDirector] winSize];
    for (b2Body* body = world->GetBodyList(); body; body= body->GetNext())
    {
        if(body->GetUserData()!=NULL)
        {
            PolygonSprite *sprite = (PolygonSprite*)body->GetUserData();
            CGPoint position = ccp(body->GetPosition().x*PTM_RATIO,body->GetPosition().y*PTM_RATIO);
            if (position.x < -64 || position.x > screen.width || position.y < -64)
            {
                if (!sprite.isOriginal)
                {
                    world->DestroyBody(sprite.body);
                    [self removeChild:sprite cleanup:YES];
                }
            }
        }
    }
}
#pragma mark GameKit delegate

-(void) achievementViewControllerDidFinish:(GKAchievementViewController *)viewController
{
	AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
	[[app navController] dismissModalViewControllerAnimated:YES];
}

-(void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
	AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
	[[app navController] dismissModalViewControllerAnimated:YES];
}

@end
